package com.onefish.toolkit;

import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.concurrent.TimeUnit;

public class NioHelper3 {
    //基于nio的文件锁，如何保证同一进程，多线程条件下文件操作的安全性
    public static void main(String[] args) {
        String filePath = "C:\\Users\\Administrator\\Desktop\\example.txt";
        Runnable fileWriter = () -> {
            try {
                RandomAccessFile file = new RandomAccessFile(filePath, "rw");
                FileChannel channel = file.getChannel();
                FileLock lock ;
                while (true){
                    try {
                        //  Exception:java.nio.channels.OverlappingFileLockException
                        //  为了保证文件操作的安全性，同一时刻只能有一个线程对文件进行操作，因此采用非阻塞式独占锁/排它锁进行加锁操作
                        lock = channel.tryLock();
                        break;
                    } catch (Exception e){
                        System.out.println(Thread.currentThread().getId() + " 当前线程获取文件锁失败，" + "其他线程已经占用该文件锁，请休眠一段时间再获取！");
                        try {
                            TimeUnit.SECONDS.sleep(2);
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                }
                // 模拟换行追加写入操作
                String content = "Thread " + Thread.currentThread().getId() + " is writing to the file.\n";
                long currentLength = file.length();
                file.seek(currentLength);
                file.write(content.getBytes());

                lock.release(); //  哪些条件会触发文件锁的释放
                channel.close();
                file.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        };

        // 创建多个线程并启动
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(fileWriter);
            thread.start();
        }
    }
}
